package com.atguigu.hbase;

import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;

/**
 * Created by Smexy on 2022/11/4
 *
 *  连接数据库的套路:
 *      ①准备一个连接，连上你的数据库服务器
 *      ②准备一个客户端对象
 *      ③使用客户端发送命令(读，写)
 *      ④如果是读，解析返回的结果
 *      ⑤用完之后，关闭连接
 *
 *
 *  JDBC：
 *      ①创建一个Connection(连接)
 *      ②准备SQL
 *      ③使用连接预编译sql，得到PaparedStatement
 *      ④填充占位符
 *      ⑤执行sql
 *      ⑥如果是读，遍历结果
 *      ⑦关闭连接
 *
 *  Connection: ①只需要创建Connection,自动维持和hbase服务器和zk的连接
 *              ②可以通过ConnectionFactory创建Connection的实例
 *                      如何去创建对象:
 *                          通过类的构造器:
 *                                 A a = new A();
 *                          会把构造器私有！
 *                             建造者模式:
 *                                  A a = new A.Builder().xxxx().xxx().build()
 *
 *                             工厂模式:
 *                                    A a = new AFactory().xxxx();
 *              ③谁创建，谁关闭，不会自动处理
 *              ④从Connection中获取
 *                      Table:  负责DML。 数据的增删改查
 *                      Admin:  负责DDL。 建表，删表，该表，列出所有表
 *               ⑤Connection的创建是重量级(耗时，耗资源)。线程安全。
 *                      可以在App中只创建一次，在不同的线程中共享。
 *
 *                     一个App只创建一个Connection。每个线程有自己的Table和Admin(创建是轻量级，不是线程安全)对象，用完就关。
 *    ---------------------------------------
 *     Table: 代表一张表。对这张表的所有操作都可以通过Table对象的API实现。
 *          put：  Table.put(Put a)
 *          get:  Table.get(Get g)
 *          scan: Table.scan(Scanner s)
 *          delete: Table.delete(Delete d)
 *
 *      工具类:
 *          Bytes:
 *                      Bytes.toBytes(T t): 把T类型转换为byte[]
 *                      Byte.toXxx(byte [] b): 把byte[]转为Xxx类型
 *
 *          CellUtil:
 *                      获取Cell中的某个属性: rowkey,cf,value
 *                      rowkey:  CellUtil.cloneRowkey(Cell c)
 */
public class HBaseUtil
{
    //单例的Connection
    private static Connection conn ;

    static {
        try {
            /*
                createConnection()
                createConnection(HBaseConfiguration.create(), null, null)

                 Configuration conf = new Configuration();
                    会自动加载类路径下 hadoop的配置文件:  core-site.xml...
                    读取类路径下 hbase的配置文件: hbase-site.xml 和hbase-default.xml
             */
            conn = ConnectionFactory.createConnection();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //获取Result中的结果打印到控制台
    public static void parseResult(Result result){

        Cell[] cells = result.rawCells();

        for (Cell cell : cells) {
            System.out.println(Bytes.toString(CellUtil.cloneRow(cell)) + "," +
                Bytes.toString(CellUtil.cloneFamily(cell)) + ":" +
                Bytes.toString(CellUtil.cloneQualifier(cell)) + "," +
                Bytes.toString(CellUtil.cloneValue(cell)) +",ts=" +
                cell.getTimestamp()
                );
        }

    }

    //根据表名获取Table
    public static Table getTable(String name) throws IOException {
        //检查名字是否合法 isBlank(xxx): 判断xxx是否是null或白字符(空格，tab,回车)
        if (StringUtils.isBlank(name)){
            throw new RuntimeException("名字非法!");
        }

        Table table = conn.getTable(TableName.valueOf(name));

        return table;
    }


    /*
            构造Put

            table/rowkey/cf:name
     */
    public static Put getPut(String rowkey,String cf,String cn,String value){
        //代表向哪一行写入
        Put put = new Put(Bytes.toBytes(rowkey));
        //向这行添加一个cell
        put.addColumn(Bytes.toBytes(cf),Bytes.toBytes(cn),Bytes.toBytes(value));

        return put;

    }

    public static void close() throws IOException {
        if (conn != null) {
            conn.close();
        }
    }




}
